ASSERT(page->count_info == 0);
/* Only add to the allocation list if the domain isn't dying. */
- if ( !test_bit(_DOMF_dying, &d->domain_flags) )
+ if ( !d->is_dying )
{
page->count_info |= PGC_allocated | 1;
if ( unlikely(d->xenheap_pages++ == 0) )
* page-table pages if we detect a referential loop.
* See domain.c:relinquish_list().
*/
- ASSERT((x & PGT_validated) ||
- test_bit(_DOMF_dying, &page_get_owner(page)->domain_flags));
+ ASSERT((x & PGT_validated) || page_get_owner(page)->is_dying);
if ( unlikely((nx & PGT_count_mask) == 0) )
{
ASSERT(page->count_info == 0);
/* Only add to the allocation list if the domain isn't dying. */
- if ( !test_bit(_DOMF_dying, &d->domain_flags) )
+ if ( !d->is_dying )
{
page->count_info |= PGC_allocated | 1;
if ( unlikely(d->xenheap_pages++ == 0) )
* page-table pages if we detect a referential loop.
* See domain.c:relinquish_list().
*/
- ASSERT((x & PGT_validated) ||
- test_bit(_DOMF_dying, &page_get_owner(page)->domain_flags));
+ ASSERT((x & PGT_validated) || page_get_owner(page)->is_dying);
if ( unlikely((nx & PGT_count_mask) == 0) )
{
void free_rma_check(struct page_info *page)
{
if (test_bit(_PGC_page_RMA, &page->count_info)) {
- if (!test_bit(_DOMF_dying, &page_get_owner(page)->domain_flags)) {
+ if (!page_get_owner(page)->is_dying) {
panic("Attempt to free an RMA page: 0x%lx\n", page_to_mfn(page));
} else {
clear_bit(_PGC_page_RMA, &page->count_info);
mfn = d->arch.p2m[pfn];
}
#ifdef DEBUG
- if (t != PFN_TYPE_NONE &&
- (d->domain_flags & DOMF_dying) &&
+ if (t != PFN_TYPE_NONE && d->is_dying &&
page_get_owner(mfn_to_page(mfn)) != d) {
printk("%s: page type: %d owner Dom[%d]:%p expected Dom[%d]:%p\n",
__func__, t,
if ( !IS_COMPAT(d) )
return 0;
- clear_bit(_DOMF_compat, &d->domain_flags);
+ d->is_compat = 0;
release_arg_xlat_area(d);
/* switch gdt */
if ( IS_COMPAT(d) )
return 0;
- set_bit(_DOMF_compat, &d->domain_flags);
+ d->is_compat = 1;
/* switch gdt */
gdt_l1e = l1e_from_page(virt_to_page(compat_gdt_table), PAGE_HYPERVISOR);
{
l1_pgentry_t gdt_l1e;
- set_bit(_DOMF_compat, &d->domain_flags);
+ d->is_compat = 1;
v->vcpu_info = (void *)&d->shared_info->compat.vcpu_info[0];
if ( nr_pages != (unsigned int)nr_pages )
ASSERT(page->count_info == 0);
/* Only add to the allocation list if the domain isn't dying. */
- if ( !test_bit(_DOMF_dying, &d->domain_flags) )
+ if ( !d->is_dying )
{
page->count_info |= PGC_allocated | 1;
if ( unlikely(d->xenheap_pages++ == 0) )
* (Note that the undestroyable active grants are not a security hole in
* Xen. All active grants can safely be cleaned up when the domain dies.)
*/
- if ( (l1e_get_flags(l1e) & _PAGE_GNTTAB) &&
- !(d->domain_flags & (DOMF_shutdown|DOMF_dying)) )
+ if ( (l1e_get_flags(l1e) & _PAGE_GNTTAB) && !d->is_shutdown && !d->is_dying )
{
MEM_LOG("Attempt to implicitly unmap a granted PTE %" PRIpte,
l1e_get_intpte(l1e));
/* A page is dirtied when its pin status is set. */
mark_dirty(d, mfn);
- /* We can race domain destruction (domain_relinquish_resources). */
+ /*
+ * We can race domain destruction (domain_relinquish_resources).
+ * NB. The dying-flag test must happen /after/ setting PGT_pinned.
+ */
if ( unlikely(this_cpu(percpu_mm_info).foreign != NULL) &&
- test_bit(_DOMF_dying, &FOREIGNDOM->domain_flags) &&
+ this_cpu(percpu_mm_info).foreign->is_dying &&
test_and_clear_bit(_PGT_pinned, &page->u.inuse.type_info) )
put_page_and_type(page);
mfn_t mfn;
HERE_I_AM;
- ASSERT(test_bit(_DOMF_dying, &d->domain_flags));
+ ASSERT(d->is_dying);
ASSERT(d != current->domain);
if ( !hap_locked_by_me(d) )
struct list_head *entry, *n;
struct page_info *pg;
- ASSERT(test_bit(_DOMF_dying, &d->domain_flags));
+ ASSERT(d->is_dying);
ASSERT(d != current->domain);
if ( !shadow_locked_by_me(d) )
return -EINVAL;
}
- if ( unlikely(test_bit(_DOMF_dying, &d->domain_flags)) )
+ if ( unlikely(d->is_dying) )
{
gdprintk(XENLOG_INFO, "Ignoring shadow op on dying domain %u\n",
d->domain_id);
{
/* Couldn't get the sl1e! Since we know the guest entries
* are OK, this can only have been caused by a failed
- * shadow_set_l*e(), which will have crashed the guest.
+ * shadow_set_l*e(), which will have crashed the guest.
* Get out of the fault handler immediately. */
- ASSERT(test_bit(_DOMF_dying, &d->domain_flags));
+ ASSERT(d->is_shutdown);
unmap_walk(v, &gw);
shadow_unlock(d);
return 0;
OFFSET(VCPU_vmx_cr2, struct vcpu, arch.hvm_vmx.cpu_cr2);
BLANK();
- OFFSET(DOMAIN_domain_flags, struct domain, domain_flags);
- DEFINE(_DOMF_compat, _DOMF_compat);
+ OFFSET(DOMAIN_is_compat, struct domain, is_compat);
BLANK();
OFFSET(VMCB_rax, struct vmcb_struct, rax);
jz int80_slow_path
movq VCPU_domain(%rbx),%rax
- btl $_DOMF_compat,DOMAIN_domain_flags(%rax)
- jc compat_int80_direct_trap
+ testb $1,DOMAIN_is_compat(%rax)
+ jnz compat_int80_direct_trap
call create_bounce_frame
jmp restore_all_guest
GET_GUEST_REGS(%rax)
movq %rax,%rsp
# create_bounce_frame() temporarily clobbers CS.RPL. Fix up.
-#ifdef CONFIG_COMPAT
movq CPUINFO_current_vcpu(%rax),%rax
movq VCPU_domain(%rax),%rax
- btl $_DOMF_compat,DOMAIN_domain_flags(%rax)
- setnc %al
+ testb $1,DOMAIN_is_compat(%rax)
+ setz %al
leal (%rax,%rax,2),%eax
orb %al,UREGS_cs(%rsp)
-#else
- orb $3,UREGS_cs(%rsp)
-#endif
# printk(domain_crash_synchronous_string)
leaq domain_crash_synchronous_string(%rip),%rdi
xorl %eax,%eax
GET_CURRENT(%rbx)
testb $3,UREGS_cs(%rsp)
jz restore_all_xen
-#ifndef CONFIG_COMPAT
- jmp test_all_events
-#else
movq VCPU_domain(%rbx),%rax
- btl $_DOMF_compat,DOMAIN_domain_flags(%rax)
- jnc test_all_events
+ testb $1,DOMAIN_is_compat(%rax)
+ jz test_all_events
jmp compat_test_all_events
-#endif
ALIGN
/* No special register assumptions. */
testb $3,UREGS_cs(%rsp)
jz restore_all_xen
leaq VCPU_trap_bounce(%rbx),%rdx
-#ifdef CONFIG_COMPAT
movq VCPU_domain(%rbx),%rax
- btl $_DOMF_compat,DOMAIN_domain_flags(%rax)
- jc compat_post_handle_exception
-#endif
+ testb $1,DOMAIN_is_compat(%rax)
+ jnz compat_post_handle_exception
testb $TBF_EXCEPTION,TRAPBOUNCE_flags(%rdx)
jz test_all_events
call create_bounce_frame
atomic_set(&d->refcnt, 1);
spin_lock_init(&d->big_lock);
spin_lock_init(&d->page_alloc_lock);
- spin_lock_init(&d->pause_lock);
INIT_LIST_HEAD(&d->page_list);
INIT_LIST_HEAD(&d->xenpage_list);
if ( !is_idle_domain(d) )
{
- set_bit(_DOMF_ctrl_pause, &d->domain_flags);
+ d->is_paused_by_controller = 1;
+ atomic_inc(&d->pause_count);
+
if ( evtchn_init(d) != 0 )
goto fail1;
+
if ( grant_table_create(d) != 0 )
goto fail2;
}
{
domain_pause(d);
- if ( test_and_set_bit(_DOMF_dying, &d->domain_flags) )
+ /* Already dying? Then bail. */
+ if ( xchg(&d->is_dying, 1) )
return;
+ /* Tear down state /after/ setting the dying flag. */
+ smp_wmb();
+
gnttab_release_mappings(d);
domain_relinquish_resources(d);
put_domain(d);
void __domain_crash(struct domain *d)
{
- if ( test_bit(_DOMF_shutdown, &d->domain_flags) )
+ if ( d->is_shutdown )
{
/* Print nothing: the domain is already shutting down. */
}
if ( d->domain_id == 0 )
dom0_shutdown(reason);
- if ( !test_and_set_bit(_DOMF_shutdown, &d->domain_flags) )
+ if ( !xchg(&d->is_shutdown, 1) )
d->shutdown_code = reason;
for_each_vcpu ( d, v )
struct domain *d = current->domain;
struct vcpu *v;
- set_bit(_DOMF_ctrl_pause, &d->domain_flags);
+ atomic_inc(&d->pause_count);
+ if ( xchg(&d->is_paused_by_controller, 1) )
+ domain_unpause(d); /* race-free atomic_dec(&d->pause_count) */
for_each_vcpu ( d, v )
vcpu_sleep_nosync(v);
struct domain **pd;
atomic_t old, new;
- BUG_ON(!test_bit(_DOMF_dying, &d->domain_flags));
+ BUG_ON(!d->is_dying);
/* May be already destroyed, or get_domain() can race us. */
_atomic_set(old, 0);
ASSERT(d != current->domain);
- spin_lock(&d->pause_lock);
- if ( d->pause_count++ == 0 )
- set_bit(_DOMF_paused, &d->domain_flags);
- spin_unlock(&d->pause_lock);
+ atomic_inc(&d->pause_count);
for_each_vcpu( d, v )
vcpu_sleep_sync(v);
void domain_unpause(struct domain *d)
{
struct vcpu *v;
- int wake;
ASSERT(d != current->domain);
- spin_lock(&d->pause_lock);
- wake = (--d->pause_count == 0);
- if ( wake )
- clear_bit(_DOMF_paused, &d->domain_flags);
- spin_unlock(&d->pause_lock);
-
- if ( wake )
+ if ( atomic_dec_and_test(&d->pause_count) )
for_each_vcpu( d, v )
vcpu_wake(v);
}
void domain_pause_by_systemcontroller(struct domain *d)
{
- struct vcpu *v;
-
- BUG_ON(current->domain == d);
-
- if ( !test_and_set_bit(_DOMF_ctrl_pause, &d->domain_flags) )
- {
- for_each_vcpu ( d, v )
- vcpu_sleep_sync(v);
- }
+ domain_pause(d);
+ if ( xchg(&d->is_paused_by_controller, 1) )
+ domain_unpause(d);
}
void domain_unpause_by_systemcontroller(struct domain *d)
{
- struct vcpu *v;
-
- if ( test_and_clear_bit(_DOMF_ctrl_pause, &d->domain_flags) )
- {
- for_each_vcpu ( d, v )
- vcpu_wake(v);
- }
+ if ( xchg(&d->is_paused_by_controller, 0) )
+ domain_unpause(d);
}
int boot_vcpu(struct domain *d, int vcpuid, vcpu_guest_context_u ctxt)
info->cpu_time = cpu_time;
info->flags = flags |
- ((d->domain_flags & DOMF_dying) ? XEN_DOMINF_dying : 0) |
- ((d->domain_flags & DOMF_shutdown) ? XEN_DOMINF_shutdown : 0) |
- ((d->domain_flags & DOMF_ctrl_pause) ? XEN_DOMINF_paused : 0) |
+ (d->is_dying ? XEN_DOMINF_dying : 0) |
+ (d->is_shutdown ? XEN_DOMINF_shutdown : 0) |
+ (d->is_paused_by_controller ? XEN_DOMINF_paused : 0) |
d->shutdown_code << XEN_DOMINF_shutdownshift;
if ( is_hvm_domain(d) )
if ( d != NULL )
{
ret = 0;
- if ( test_and_clear_bit(_DOMF_shutdown, &d->domain_flags) )
+ if ( xchg(&d->is_shutdown, 0) )
for_each_vcpu ( d, v )
vcpu_wake(v);
rcu_unlock_domain(d);
}
/* Check if some VCPU might be polling for this event. */
- if ( unlikely(test_bit(_DOMF_polling, &d->domain_flags)) &&
- likely(test_and_clear_bit(_DOMF_polling, &d->domain_flags)) )
+ if ( unlikely(d->is_polling) && likely(xchg(&d->is_polling, 0)) )
{
for_each_vcpu ( d, v )
if ( test_and_clear_bit(_VCPUF_polling, &v->vcpu_flags) )
get_page_and_type(mfn_to_page(frame), rd,
PGT_writable_page))) )
{
- if ( !test_bit(_DOMF_dying, &rd->domain_flags) )
+ if ( !rd->is_dying )
gdprintk(XENLOG_WARNING, "Could not pin grant frame %lx\n", frame);
rc = GNTST_general_error;
goto undo_out;
* headroom. Also, a domain mustn't have PGC_allocated
* pages when it is dying.
*/
- if ( unlikely(test_bit(_DOMF_dying, &e->domain_flags)) ||
+ if ( unlikely(e->is_dying) ||
unlikely(e->tot_pages >= e->max_pages) ||
unlikely(!gnttab_prepare_for_transfer(e, d, gop.ref)) )
{
- if ( !test_bit(_DOMF_dying, &e->domain_flags) )
+ if ( !e->is_dying )
gdprintk(XENLOG_INFO, "gnttab_transfer: "
"Transferee has no reservation "
"headroom (%d,%d) or provided a bad grant ref (%08x) "
- "or is dying (%lx)\n",
- e->tot_pages, e->max_pages, gop.ref, e->domain_flags);
+ "or is dying (%d)\n",
+ e->tot_pages, e->max_pages, gop.ref, e->is_dying);
spin_unlock(&e->page_alloc_lock);
rcu_unlock_domain(e);
page->count_info &= ~(PGC_count_mask|PGC_allocated);
"source frame %lx invalid.\n", s_frame);
if ( !get_page(mfn_to_page(s_frame), sd) )
{
- if ( !test_bit(_DOMF_dying, &sd->domain_flags) )
+ if ( !sd->is_dying )
gdprintk(XENLOG_WARNING, "Could not get src frame %lx\n", s_frame);
rc = GNTST_general_error;
goto error_out;
"destination frame %lx invalid.\n", d_frame);
if ( !get_page_and_type(mfn_to_page(d_frame), dd, PGT_writable_page) )
{
- if ( !test_bit(_DOMF_dying, &dd->domain_flags) )
+ if ( !dd->is_dying )
gdprintk(XENLOG_WARNING, "Could not get dst frame %lx\n", d_frame);
rc = GNTST_general_error;
goto error_out;
struct active_grant_entry *act;
struct grant_entry *sha;
- BUG_ON(!test_bit(_DOMF_dying, &d->domain_flags));
+ BUG_ON(!d->is_dying);
for ( handle = 0; handle < gt->maptrack_limit; handle++ )
{
{
printk("General information for domain %u:\n", d->domain_id);
cpuset_print(tmpstr, sizeof(tmpstr), d->domain_dirty_cpumask);
- printk(" flags=%lx refcnt=%d nr_pages=%d xenheap_pages=%d "
+ printk(" refcnt=%d nr_pages=%d xenheap_pages=%d "
"dirty_cpus=%s\n",
- d->domain_flags, atomic_read(&d->refcnt),
+ atomic_read(&d->refcnt),
d->tot_pages, d->xenheap_pages, tmpstr);
printk(" handle=%02x%02x%02x%02x-%02x%02x-%02x%02x-"
"%02x%02x-%02x%02x%02x%02x%02x%02x vm_assist=%08lx\n",
/*
* Only support exchange on calling domain right now. Otherwise there are
- * tricky corner cases to consider (e.g., DOMF_dying domain).
+ * tricky corner cases to consider (e.g., dying domain).
*/
if ( unlikely(exch.in.domid != DOMID_SELF) )
{
spin_lock(&d->page_alloc_lock);
- if ( unlikely(test_bit(_DOMF_dying, &d->domain_flags)) )
+ if ( unlikely(d->is_dying) )
{
gdprintk(XENLOG_INFO, "Cannot assign page to domain%d -- dying.\n",
d->domain_id);
spin_unlock_recursive(&d->page_alloc_lock);
- if ( likely(!test_bit(_DOMF_dying, &d->domain_flags)) )
+ if ( likely(!d->is_dying) )
{
free_heap_pages(pfn_dom_zone_type(page_to_mfn(pg)), pg, order);
}
/* These operations must occur in order. */
set_bit(_VCPUF_blocked, &v->vcpu_flags);
set_bit(_VCPUF_polling, &v->vcpu_flags);
- set_bit(_DOMF_polling, &d->domain_flags);
+ smp_wmb();
+ d->is_polling = 1;
+ smp_wmb();
/* Check for events /after/ setting flags: avoids wakeup waiting race. */
for ( i = 0; i < sched_poll->nr_ports; i++ )
unsigned int xenheap_pages; /* # pages allocated from Xen heap */
/* Scheduling. */
- int shutdown_code; /* code value from OS (if DOMF_shutdown) */
void *sched_priv; /* scheduler-specific data */
struct domain *next_in_list;
struct rangeset *iomem_caps;
struct rangeset *irq_caps;
- unsigned long domain_flags;
-
/* Is this an HVM guest? */
bool_t is_hvm;
/* Is this guest fully privileged (aka dom0)? */
bool_t is_privileged;
/* Is this guest being debugged by dom0? */
bool_t debugger_attached;
+ /* Is a 'compatibility mode' guest (semantics are arch specific)? */
+ bool_t is_compat;
+ /* Are any VCPUs polling event channels (SCHEDOP_poll)? */
+ bool_t is_polling;
+ /* Is this guest dying (i.e., a zombie)? */
+ bool_t is_dying;
+ /* Domain is paused by controller software? */
+ bool_t is_paused_by_controller;
- spinlock_t pause_lock;
- unsigned int pause_count;
+ /* Guest has shut down (inc. reason code)? */
+ bool_t is_shutdown;
+ int shutdown_code;
+
+ atomic_t pause_count;
unsigned long vm_assist;
#define _VCPUF_migrating 13
#define VCPUF_migrating (1UL<<_VCPUF_migrating)
-/*
- * Per-domain flags (domain_flags).
- */
- /* Guest shut itself down for some reason. */
-#define _DOMF_shutdown 0
-#define DOMF_shutdown (1UL<<_DOMF_shutdown)
- /* Death rattle. */
-#define _DOMF_dying 1
-#define DOMF_dying (1UL<<_DOMF_dying)
- /* Domain is paused by controller software. */
-#define _DOMF_ctrl_pause 2
-#define DOMF_ctrl_pause (1UL<<_DOMF_ctrl_pause)
- /* Are any VCPUs polling event channels (SCHEDOP_poll)? */
-#define _DOMF_polling 3
-#define DOMF_polling (1UL<<_DOMF_polling)
- /* Domain is paused by the hypervisor? */
-#define _DOMF_paused 4
-#define DOMF_paused (1UL<<_DOMF_paused)
- /* Domain is a compatibility one? */
-#define _DOMF_compat 5
-#define DOMF_compat (1UL<<_DOMF_compat)
-
static inline int vcpu_runnable(struct vcpu *v)
{
return ( !(v->vcpu_flags &
VCPUF_paused |
VCPUF_blocked_in_xen |
VCPUF_migrating )) &&
- !(v->domain->domain_flags &
- ( DOMF_shutdown |
- DOMF_ctrl_pause |
- DOMF_paused )));
+ (atomic_read(&v->domain->pause_count) == 0) );
}
void vcpu_pause(struct vcpu *v);
#define IS_PRIV(_d) ((_d)->is_privileged)
#ifdef CONFIG_COMPAT
-#define IS_COMPAT(_d) \
- (test_bit(_DOMF_compat, &(_d)->domain_flags))
+#define IS_COMPAT(_d) ((_d)->is_compat)
#else
#define IS_COMPAT(_d) 0
#endif
#define write_lock(_lock) _raw_write_lock(_lock)
#define write_unlock(_lock) _raw_write_unlock(_lock)
+/* Ensure a lock is quiescent between two critical operations. */
+static inline void spin_barrier(spinlock_t *lock)
+{
+ spin_lock(lock);
+ spin_unlock(lock);
+}
+
#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED
#define DEFINE_RWLOCK(x) rwlock_t x = RW_LOCK_UNLOCKED